package problems;

import interfaces.EulerProblemInterface;
import utility.DivisibilityChecker;
import utility.ProblemSpecifics;

public class EulerProblem005 implements EulerProblemInterface {

	private ProblemSpecifics problemSpecifics;

	private static final int DIVISIBILITY_BELOW_THIS_IS_IMPLIED = 11;
	private static final int BIGGEST_DIVISOR = 20;

	private boolean divisibleByAllNumbersChecked;
	private int currentNumberToBeChecked;

	public EulerProblem005() {
		String problemStatement = "What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?";
		problemSpecifics = new ProblemSpecifics(problemStatement);
		currentNumberToBeChecked = BIGGEST_DIVISOR;
	}

	public void solve() {

		while (resultNotFound()) {
			checkForDivisibilityAndSetResultIfFound();
			currentNumberToBeChecked = currentNumberToBeChecked
					+ BIGGEST_DIVISOR;
		}

	}

	private void checkForDivisibilityAndSetResultIfFound() {
		if (divisibleByAllTheNumbers()) {
			problemSpecifics.setResultAndMarkSolved(currentNumberToBeChecked);
		}
	}

	private boolean resultNotFound() {
		return !problemSpecifics.isSolved();
	}

	private boolean divisibleByAllTheNumbers() {

		divisibleByAllNumbersChecked = true;
		int currentDivisor = BIGGEST_DIVISOR;

		while (divisibleByAllNumbersCheckedAndEndOfSearchNotReached(currentDivisor)) {
			if (currentNumberNotEvenlyDivisibleBy(currentDivisor)) {
				divisibleByAllNumbersChecked = false;
			}
			currentDivisor--;
		}
		return divisibleByAllNumbersChecked;
	}

	private boolean divisibleByAllNumbersCheckedAndEndOfSearchNotReached(
			int currentDivisor) {
		boolean endOfSearchNotReached = currentDivisor >= DIVISIBILITY_BELOW_THIS_IS_IMPLIED;
		return divisibleByAllNumbersChecked && endOfSearchNotReached;
	}

	private boolean currentNumberNotEvenlyDivisibleBy(int currentDivisor) {

		boolean isEvenlyDivisible = DivisibilityChecker
				.firstEvenlyDividesSecond(currentNumberToBeChecked,
						currentDivisor);
		return !isEvenlyDivisible;

	}

	public long reportResult() {
		return problemSpecifics.reportResult();
	}

	public ProblemStatus reportStatus() {
		return new ProblemStatus(problemSpecifics.isSolved());
	}

	public String stateTheProblem() {
		return problemSpecifics.stateTheProblem();
	}

}
